비용 함수 목표 =
- alpha: 학습 데이터 적합 정도와 회귀 계수 값의 크기 제어를 수행하는 튜닝 파라미터
- alpha가 0(또는 매우 작은 값)이라면 비용 함수 식은 기존과 동일한 가 됨
- alpha가 무한대(또는 매우 큰 값)이라면 비용 함수 식은 에 비해 값이 너무 커지므로 W 값을 0 또는 매우 작게 만들어야 Cost가 최소화 되는 비용 함수 목표를 달성할 수 있음 → alpha 값을 크게 하면 비용 함수는 회귀 계수 W의 값을 작게 해 과적합을 개선할 수 있으며 alpha 값을 작게 하면 회귀 계수 W의 값이 커져도 어느 정도 상쇄가 가능하므로 학습 데이터 적합을 더 개선할 수 있음
alpha를 0에서부터 지속적으로 값을 증가시키면 회귀 계수 값의 크기를 감소시킬 수 있음
규제(Regularization): 비용 함수에 alpha 값으로 패널티를 부여해 회귀 계수 값의 크기를 감소해 과적합을 개선하는 방식
규제 방식
L2 규제:
| | W | 와 같이 W 제곱에 패널티를 부여하는 방식 ← 릿지(Ridge) 회귀| 2 2 L1 규제:
| | W | 와 같이 W의 절대값에 패널티를 부여, 영향력이 크지 않은 회귀 계수 값을 0으로 변환 ← 라쏘(Lasso) 회귀| 1
(2) 릿지 회귀
- 사이킷런은 Ridge 클래스로 릿지 회귀를 구현
- 주요 생성 파라미터: alpha, 릿지 회귀의 alpha L2 규제 계수에 해당
- 보스턴 주택 가격을 Ridge 클래스로 예측하고, cross_val_score()로 평가하기
1 | # 앞의 LinearRegression예제에서 분할한 feature 데이터 셋인 X_data과 Target 데이터 셋인 Y_target 데이터셋을 그대로 이용 |
Boston 데이타셋 크기 : (506, 14)
5 folds 의 개별 Negative MSE scores: [-11.422 -24.294 -28.144 -74.599 -28.517]
5 folds 의 개별 RMSE scores : [3.38 4.929 5.305 8.637 5.34 ]
5 folds 의 평균 RMSE : 5.518
- 결과 해석
- 릿지의 5개 폴드 세트 평균 RMSE: 5.524
- 앞 예제(규제 없는 LinearRegression) 평균인 5.836보다 뛰어난 예측 성능을 보임
- 릿지의 alpha 값을 0, 0.1, 1, 10, 100으로 변화시키며 RMSE와 회귀 계수 값 변화 살펴보기
1 | # Ridge에 사용될 alpha 파라미터의 값들을 정의 |
alpha 0 일 때 5 folds 의 평균 RMSE : 5.829
alpha 0.1 일 때 5 folds 의 평균 RMSE : 5.788
alpha 1 일 때 5 folds 의 평균 RMSE : 5.653
alpha 10 일 때 5 folds 의 평균 RMSE : 5.518
alpha 100 일 때 5 folds 의 평균 RMSE : 5.330
- 결과 해석
- alpha가 100일 때, 평균 RMSE가 5.332로 가장 좋음
- alpha 값 변화에 따른 피처의 회귀 계수 값을 가로 막대 그래프로 시각화
1 | # 각 alpha에 따른 회귀 계수 값을 시각화하기 위해 5개의 열로 된 맷플롯립 축 생성 |

- 결과 해석
- alpha 값을 계속 증가시킬수록 회귀 계수 값은 지속적으로 작아짐
- 특히, NOX 피처의 경우 alpha 값을 계속 증가시킴에 따라 회귀 계수가 크게 작아지고 있음
- DataFrame에 저장된 alpha 값 변화에 따른 릿지 회귀 계수 값 구하기
1 | ridge_alphas = [0 , 0.1 , 1 , 10 , 100] |
| alpha:0 | alpha:0.1 | alpha:1 | alpha:10 | alpha:100 | |
|---|---|---|---|---|---|
| RM | 3.809865 | 3.818233 | 3.854000 | 3.702272 | 2.334536 |
| CHAS | 2.686734 | 2.670019 | 2.552393 | 1.952021 | 0.638335 |
| RAD | 0.306049 | 0.303515 | 0.290142 | 0.279596 | 0.315358 |
| ZN | 0.046420 | 0.046572 | 0.047443 | 0.049579 | 0.054496 |
| INDUS | 0.020559 | 0.015999 | -0.008805 | -0.042962 | -0.052826 |
| B | 0.009312 | 0.009368 | 0.009673 | 0.010037 | 0.009393 |
| AGE | 0.000692 | -0.000269 | -0.005415 | -0.010707 | 0.001212 |
| TAX | -0.012335 | -0.012421 | -0.012912 | -0.013993 | -0.015856 |
| CRIM | -0.108011 | -0.107474 | -0.104595 | -0.101435 | -0.102202 |
| LSTAT | -0.524758 | -0.525966 | -0.533343 | -0.559366 | -0.660764 |
| PTRATIO | -0.952747 | -0.940759 | -0.876074 | -0.797945 | -0.829218 |
| DIS | -1.475567 | -1.459626 | -1.372654 | -1.248808 | -1.153390 |
| NOX | -17.766611 | -16.684645 | -10.777015 | -2.371619 | -0.262847 |
- 결과 해석
- alpha 값이 증가하며 회귀 계소가 지속적으로 작아짐
- 단, 릿지 회귀는 회귀 계수를 0으로 만들지 않음
(3) 라쏘 회귀
- 라쏘 회귀: W의 절댓값에 패널티를 부여하는 L1 규제를 선형 회귀에 적용한 것
- L1 규제는 를 의미하며, 라쏘 회귀 비용함수 목표는 RSS(W) + 식을 최소화하는 W를 찾는 것
- L2 규제가 회귀 계쑤 크기를 감소시키는 데 반해, L1 규제는 불필요한 회귀 계수를 급격히 감소시켜 0으로 만들고 제거함
- L1 규제는 적절한 피처만 회귀에 포함시키는 피처 선택의 득성을 가짐
- 사이킷런은 Lasso 클래스로 라쏘 회귀를 구현
- 주요 파라미터: alpha, 라쏘 회귀의 alpha L1 규제 계수에 해당
- Lasso 클래스로 라쏘의 alpha 값을 변화시키며 RMSE와 각 피처의 회귀 계수 출력하기
1 | from sklearn.linear_model import Lasso, ElasticNet |
1 | # 라쏘에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출 |
####### Lasso #######
alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.612
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.615
alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.669
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.776
alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.189
- 결과 해석
- alpha가 0.07일 때, 가장 좋은 평균 RMSE를 보여줌
- alpha 값에 따른 피처별 회귀 계수
1 | # 반환된 coeff_lasso_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력 |
| alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
|---|---|---|---|---|---|
| RM | 3.789725 | 3.703202 | 2.498212 | 0.949811 | 0.000000 |
| CHAS | 1.434343 | 0.955190 | 0.000000 | 0.000000 | 0.000000 |
| RAD | 0.270936 | 0.274707 | 0.277451 | 0.264206 | 0.061864 |
| ZN | 0.049059 | 0.049211 | 0.049544 | 0.049165 | 0.037231 |
| B | 0.010248 | 0.010249 | 0.009469 | 0.008247 | 0.006510 |
| NOX | -0.000000 | -0.000000 | -0.000000 | -0.000000 | 0.000000 |
| AGE | -0.011706 | -0.010037 | 0.003604 | 0.020910 | 0.042495 |
| TAX | -0.014290 | -0.014570 | -0.015442 | -0.015212 | -0.008602 |
| INDUS | -0.042120 | -0.036619 | -0.005253 | -0.000000 | -0.000000 |
| CRIM | -0.098193 | -0.097894 | -0.083289 | -0.063437 | -0.000000 |
| LSTAT | -0.560431 | -0.568769 | -0.656290 | -0.761115 | -0.807679 |
| PTRATIO | -0.765107 | -0.770654 | -0.758752 | -0.722966 | -0.265072 |
| DIS | -1.176583 | -1.160538 | -0.936605 | -0.668790 | -0.000000 |
- 결과 해석
- alpha의 크기가 증가함에 따라 일부 피처 회귀 계수는 아예 0으로 바뀜
- NOX 속성은 alpha가 0.07일 때부터 회귀 계수가 0이며, alpha를 증가시키며 INDUS, CHAS와 같은 속성 회귀 계수가 0으로 바뀜
- 회귀 계수가 0인 피처는 회귀 식에서 제외되며 피처 선택의 효과를 얻을 수 있음
(4) 엘라스틱넷 회귀
- 엘라스틱넷(Elastic Net) 회귀: L2 규제와 L1 규제를 결합한 회귀
- 엘라스틱넷 회귀 비용함수 목표: 식을 최소화하는 W를 찾는 것
- 엘라스틱넷은 라쏘 회귀가 상관관계가 높은 피처들의 경우에, 중요 피처만을 선택하고 다른 피처 회귀 계수는 0으로 만드는 성향이 강함
- alpha 값에 따라 회귀 계쑤 값이 급격히 변동할 수 있는데, 엘라스틱넷 회귀는 이를 완화하기 위해 L2 규제를 라쏘 회귀에 추가한 것
- 엘라스틱넷 회귀의 단점은 L1과 L2 규제가 결합된 규제로 인해 수행 시간이 상대적으로 오래 걸림
- 사이킷런은 Elastic Net 클래스로 엘라스틱넷 회귀를 구현
- 주요 파라미터: aplha, l1_ration
- Elastic Net 클래스의 aplha는 Ridge와 Lasso 클래스의 alpha 값과는 다름
- 엘라스틱넷 규제는 a * L1 + b * L2로 정의될 수 있으며, 이 때 a는 L1 규제의 alpha값, b는 L2 규제의 alpha 값
- 따라서 ElasticNet 클래스의 alpha 파라미터 값은 a + b 값
- ElasticNet 클래스의 l1_ratio 파라미터 값은 a / (a + b)
- l1_ratio가 0이면 a가 0이므로 L2 규제와 동일하고, l1_ratio가 1이면 b가 0이므로 L1 규제와 동일
- Elastic Net 클래스로 엘라스틱넷 alpha 값을 변화시키며 RMSE와 각 피처의 회귀 계수 출력하기
- l1_ratio를 0.7로 고정한 이유: 단순히 alpha 값의 변화만 살피기 위해
1 | # 엘라스틱넷에 사용될 alpha 파라미터의 값들을 정의하고 get_linear_reg_eval() 함수 호출 |
####### ElasticNet #######
alpha 0.07일 때 5 폴드 세트의 평균 RMSE: 5.542
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.526
alpha 0.5일 때 5 폴드 세트의 평균 RMSE: 5.467
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.597
alpha 3일 때 5 폴드 세트의 평균 RMSE: 6.068
1 | # 반환된 coeff_elastic_df를 첫번째 컬럼순으로 내림차순 정렬하여 회귀계수 DataFrame출력 |
| alpha:0.07 | alpha:0.1 | alpha:0.5 | alpha:1 | alpha:3 | |
|---|---|---|---|---|---|
| RM | 3.574162 | 3.414154 | 1.918419 | 0.938789 | 0.000000 |
| CHAS | 1.330724 | 0.979706 | 0.000000 | 0.000000 | 0.000000 |
| RAD | 0.278880 | 0.283443 | 0.300761 | 0.289299 | 0.146846 |
| ZN | 0.050107 | 0.050617 | 0.052878 | 0.052136 | 0.038268 |
| B | 0.010122 | 0.010067 | 0.009114 | 0.008320 | 0.007020 |
| AGE | -0.010116 | -0.008276 | 0.007760 | 0.020348 | 0.043446 |
| TAX | -0.014522 | -0.014814 | -0.016046 | -0.016218 | -0.011417 |
| INDUS | -0.044855 | -0.042719 | -0.023252 | -0.000000 | -0.000000 |
| CRIM | -0.099468 | -0.099213 | -0.089070 | -0.073577 | -0.019058 |
| NOX | -0.175072 | -0.000000 | -0.000000 | -0.000000 | -0.000000 |
| LSTAT | -0.574822 | -0.587702 | -0.693861 | -0.760457 | -0.800368 |
| PTRATIO | -0.779498 | -0.784725 | -0.790969 | -0.738672 | -0.423065 |
| DIS | -1.189438 | -1.173647 | -0.975902 | -0.725174 | -0.031208 |
- 결과 해석
- alpha 0.5일 때, RMSE가 5.468로 가장 좋은 예측 성능을 보임
- alpha 값에 따른 피처들의 회귀 계수 값이 라쏘보다는 0 되는 값이 적음
(5) 선형 회귀 모델을 위한 데이터 변환
- 선형 회귀 모델과 같은 선형 모델은 일반적으로 피처와 타겟 간에 선형의 관계가 있다 가정하고, 이러한 최적의 선형함수를 찾아내 결과를 예측
- 선형 회귀 모델은 피처값과 타겟값의 분포가 정규 분포(즉 평균을 중심으로 종 모양으로 데이터 값이 분포된 형태) 형태를 매우 선호함
- 타겟값의 경우 정규 분포 형태가 아니라 특정값의 분포가 치우친 왜곡된 형태의 분포도일 경우 예측 성능에 부정적인 영향을 미칠 가능성이 높음
- 피처값 역시 왜곡된 분포도로 인해 예측 성능에 부정적인 영향을 미칠 수 있음
- 일반적으로 선형 회귀 모델을 적용하기전에 데이터에 대한 스케일링/정규화 작업을 수행함
- 단, 스케일링/정규화 작업을 선행한다고 해서 무조건 예측 성능이 향상되는 것은 아니며 중요한 피처들이나 타겟값의 분포도가 심하게 왜곡됐을 경우에 이러한 변환 작업을 수행함
- 피처 데이터 셋과 타겟 데이터 셋에 이러한 스케일링/정규화 작업을 수행하는 방법이 다름
- 사이킷런을 이용해 피처 데이터 세트에 적용하는 방법 세 가지
StandardScaler 클래스를 이용해 평균이 0, 분산이 1인 표준 정규 분포를 가진 데이터 셋으로 변환하거나 MinMaxScaler 클래스를 이용해 최소값이 0이고 최대값이 1인 값으로 정규화를 수행
스케일링/정규화를 수행한 데이터 셋에 다시 다항 특성을 적용하여 변환하는 방법이다. 보통 1번 방법을 통해 예측 성능에 향상이 없을 경우 이와 같은 방법을 적용
원래 값에 log 함수를 적용하면 보다 정규 분포에 가까운 형태로 값이 분포(= 로그 변환)된다. 실제로 선형 회귀에서는 앞서 소개한 1,2번 방법보다 로그 변환이 훨씬 많이 사용되는 변환 방법(1번 방법: 예측 성능 향상을 크게 기대하기 어려운 경우가 많음, 2번 방법: 피처 개수가 매우 많을 경우에는 다항 변환으로 생성되는 피처의 개수가 기하급수로 늘어나서 과적합의 이슈가 발생할 수 있음)
- 타겟값의 경우 일반적으로 로그 변환을 적용
- 결정값을 정규 분포나 다른 정규값으로 변환하면 변환된 값을 다시 원본 타겟값으로 원복하기 어려울 수 있음
- 왜곡된 분포도 형태의 타겟값을 로그 변환하여 예측 성능 향상이 된 경우가 많은 사례에서 검증되었기 때문에 타겟값의 경우는 로그 변환을 적용
- 보스턴 주택가격 피처 데이터 세트에 표준 정규 분포 변환, 최댓값/최솟값 정규화, 로그 변환을 적용한 후 RMSE로 각 경우별 예측 성능 측정하기
- 사용 함수: get_scaled_data()
- method 인자로 변환 방법을 결정하며, 표준 정규 분포 변환(Standard), 최댓값/최솟값 정규와(MinMax), 로그 변환(Log) 중에 하나를 선택
- p_degree: 다항식 특성을 추가할 때, 다항식 차수가 입력됨 (2를 넘기지 않음)
- np.log1p(): log() 함수만 적용하면 언더 플로우가 발생하기 쉬워 1 + log() 함수를 적용
1 | from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures |
1 | # Ridge의 alpha값을 다르게 적용하고 다양한 데이터 변환방법에 따른 RMSE 추출. |
(506, 13) (506, 13)
## 변환 유형:None, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.788
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.653
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.518
alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.330
(506, 13) (506, 13)
## 변환 유형:Standard, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.826
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.803
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.637
alpha 100일 때 5 폴드 세트의 평균 RMSE: 5.421
(506, 104) (506, 13)
## 변환 유형:Standard, Polynomial Degree:2
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 8.827
alpha 1일 때 5 폴드 세트의 평균 RMSE: 6.871
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.485
alpha 100일 때 5 폴드 세트의 평균 RMSE: 4.634
(506, 13) (506, 13)
## 변환 유형:MinMax, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.764
alpha 1일 때 5 폴드 세트의 평균 RMSE: 5.465
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.754
alpha 100일 때 5 폴드 세트의 평균 RMSE: 7.635
(506, 104) (506, 13)
## 변환 유형:MinMax, Polynomial Degree:2
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 5.298
alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.323
alpha 10일 때 5 폴드 세트의 평균 RMSE: 5.185
alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.538
(506, 13) (506, 13)
## 변환 유형:Log, Polynomial Degree:None
alpha 0.1일 때 5 폴드 세트의 평균 RMSE: 4.770
alpha 1일 때 5 폴드 세트의 평균 RMSE: 4.676
alpha 10일 때 5 폴드 세트의 평균 RMSE: 4.836
alpha 100일 때 5 폴드 세트의 평균 RMSE: 6.241
- 결과 해석
- 표준 정규 분포와 최솟값/최댓값 정규화로 피처 데이터 세트를 변경해도 성능상의 개선은 없음
- 표준 정규 분포로 일차 변환 후 2차 다항식 변환 시, alpha = 100에서 4.631로 성능 개선
- 최솟값/최댓값 정규화로 일차 변환 후 2차 다항식 변환 시, aplha = 1에서 4.320으로 성능 개선
- 단, 다항식 변환은 피처 개수가 많을 경우 적용하기 힘들며, 데이터 건수가 많아지면 시간이 많이 소모되어 적용하기에 한계가 있음
- 반면, 로그 변환은 alpha가 0.1, 1, 10인 경우 모두 성능이 좋게 향상됨
- 일반적으로 선형 회귀를 적용하려는 데이터 세트에, 데이터 값 분포가 심하게 왜곡되어 있을 경우에, 로그 변환을 적용하는 편이 더 좋은 결과를 기대할 수 있음
07. 로지스틱 회귀
- 로지스틱 회귀: 선형 회귀 방식을 분류에 적용한 알고리즘 → ‘분류’에 사용
- 선형 회귀 계열이나, 선형 회귀와 다른 점은 학습을 통해 선형 함수의 회귀 최적선을 찾지 않고 시그모이드(Sigmoid) 함수 최적선을 찾고 시그모이드 함수 반환 값을 확률로 간주하여 확률에 따라 분류를 결정하는 것

시그모이드 함수
- y = $\frac{1}{1+e-x}$ (-x는 제곱)
- 시그모이드 함수는 x 값이 +, -로 아무리 커지거나 작아져도 y 값은 0과 1 사이 값만 반환
- x 값이 커지면 1에 근사하며 x 값이 작아지면 0에 근사
- x가 0일 때는 0.5
회귀 분제를 분류 문제에 적용하기
- 종양의 크기에 따라 악성 종양인지(Yes = 1), 아닌지(No = 0)를 회귀를 이용하여 1과 0 값으로 예측하는 것
- 종양 크기에 따라 악성될 확률이 높다고 하면 아래 왼쪽 그림과 같이 분포하며 선형 회귀 선을 그릴 수 있으나, 해당 회귀 라인은 0과 1을 제대로 분류하지 못함
- 오른쪽 그림처럼 시그모이드 함수를 이용하면 조금 더 정확하게 0과 1을 분류할 수 있음

- 로지스틱 회귀로 암 여부 판단하기: 위스콘신 유방암 데이터 세트 이용
1 | import pandas as pd |
1 | from sklearn.preprocessing import StandardScaler |
- 로지스틱 회귀로 학습 및 예측하고, 정확도와 ROC-AUC 값 구하기
1 | from sklearn.metrics import accuracy_score, roc_auc_score |
accuracy: 0.977
roc_auc: 0.972
- 사이킷런 LogisticRegression 클래스의 주요 하이퍼 파라미터로 penalty와 C가 존재
- penalty는 규제의 유형을 설정하며 ‘l2’로 설정 시 L2 규제를, ‘l1’으로 설정 시 L1 규제를 뜻함
- C는 규제 강도를 조절하는 alpha 값의 역수로 C = $\frac{1}{alpha}$
- C 값이 작을수록 규제 강도가 큼을 의미
- 위스콘신 데이터 세트에서 해당 하이퍼 파라미터를 최적화하기
1 | from sklearn.model_selection import GridSearchCV |
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
최적 하이퍼 파라미터:{'C': 1, 'penalty': 'l2'}, 최적 평균 정확도:0.975
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details:
Traceback (most recent call last):
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
estimator.fit(X_train, y_train, **fit_params)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 1304, in fit
solver = _check_solver(self.solver, self.penalty, self.dual)
File "C:\Users\naeun\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py", line 442, in _check_solver
raise ValueError("Solver %s supports only 'l2' or 'none' penalties, "
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
warnings.warn("Estimator fit failed. The score on this train-test"
- 로지스틱 회귀는 가볍고 빠르며, 이진 분류 예측 성능까지 뛰어남
- 이진 분류의 기본 모델로 사용하는 경우가 많음
- 로지스틱 회귀는 희소한 데이터 세트 분류에서도 뛰어난 성능을 보임
- 텍스트 분류에서도 자주 사용
08. 회귀 트리
회귀 함수를 기반으로 하지 않고, 결정 트리와 같이 트리를 기반으로 하는 회귀 방식 소개
트리 기반이 회귀: 회귀 트리를 이용하는 것
- 회귀를 위한 트리를 생성하고 이를 기반으로 회귀를 예측하는 것
- 4장 분류에서 언급한 분류 트리와 비슷하나, 리프 노트에서 예측 결정 값을 만드는 과정에 차이가 있음
- 분류 트리는 특정 클래스 레이블을 결정하나, 회귀 트리는 리프 노드에 속한 데이터 값의 평균값을 구해 회귀 예측값을 계산
- 예시(p.335-336)
- 피처가 단 하나인 X 피처 데이터 세트와 결정값 Y가 2차원 평면에 있다고 가정
- 데이터 세트의 X 피처를 결정 트리 기반으로 분할하면 X값의 균일도를 반영한 지니 계수에 따라 분할됨
- 루트 노드를 Split 0 기준으로 분할하고, 분할된 규칙 노드에서 다시 Split 1과 Split 2 규칙 노드로 분할할 수 있음
- Split 2는 다시 재귀적으로 Split 3 규칙 노드로 트리 규칙으로 변환될 수 있음
- 리프 노드 생성 기준에 부합하는 트리 분할이 완료됐다면, 리프 노드에 소속된 데이터 값의 평균값을 구해 최종적으로 리프 노드에 결정 값으로 할당함
- 사이킷런 트리 기반 회귀와 분류의 Estimator 클래스
| 알고리즘 | 회귀 Estimator 클래스 | 분류 Estimator 클래스 |
|---|---|---|
| Decision Tree | DecisionTreeRegressor | DecisionTreeClassifier |
| Gradient Boosting | GradientBoostingRegressor | GradientBoostingClassifier |
| XGBoost | XGBRegressor | XGBClassifier |
| LightGBM | LGBMRegressor | LGBMClassifier |
- 사이킷런 랜덤 포레스트 회귀 트리인 RandomForestRegressor로 보스턴 주택 가격 예측 수행하기
1 | from sklearn.datasets import load_boston |
5 교차 검증의 개별 Negative MSE scores: [ -7.88 -13.14 -20.57 -46.23 -18.88]
5 교차 검증의 개별 RMSE scores : [2.81 3.63 4.54 6.8 4.34]
5 교차 검증의 평균 RMSE : 4.423
- 결정 트리, GBM, XGBoost, LightGBM의 Regressor을 모두 이용해 보스턴 주택 가격 예측 수행
- 사용 함수: get_model_cv_prediction()
- 입력 모델과 데이터 세트를 입력 받아, 교차 검증으로 평균 RMSE를 계산하는 함수
1 | def get_model_cv_prediction(model, X_data, y_target): |
- 다양한 유형의 회귀 트리를 생성하고, 보스턴 주택 가격 예측하기
1 | from sklearn.tree import DecisionTreeRegressor |
##### DecisionTreeRegressor #####
5 교차 검증의 평균 RMSE : 5.978
##### RandomForestRegressor #####
5 교차 검증의 평균 RMSE : 4.423
##### GradientBoostingRegressor #####
5 교차 검증의 평균 RMSE : 4.269
##### XGBRegressor #####
5 교차 검증의 평균 RMSE : 4.251
##### LGBMRegressor #####
5 교차 검증의 평균 RMSE : 4.646
- feature_importances_를 이용해 보스턴 주택 가격 모델의 피처별 중요도 시각화하기
- 회귀 트리 Regressor 클래스는 선형 회귀와 다른 처리 방식으로, 회귀 계수를 제공하는 coef_ 속성이 없으나, feature_importances_를 이용해 피처별 중요도를 알 수 있음
1 | import seaborn as sns |
<matplotlib.axes._subplots.AxesSubplot at 0x1d019a2c850>

- 회귀 트리 Regressor가 예측값을 판단하는 방법을 선형 회귀와 비교하여 시각화하기
- 보스턴 데이터 세트를 100개만 샘플링하고 RM과 PRICE 칼럼만 추출
- 2차원 평면상에서 X축에 독립변수인 RM, Y축에 종속변수인 PRICE만 가지고 더 직관적으로 예측값을 시각화하기 위한 것
1 | import matplotlib.pyplot as plt |
(100, 2)
<matplotlib.collections.PathCollection at 0x1d01ef6b520>

- LinearRegression과 DecisionTreeRegressor를 max_depth 2, 7로 학습하기
1 | import numpy as np |
1 | fig , (ax1, ax2, ax3) = plt.subplots(figsize=(14,4), ncols=3) |
[<matplotlib.lines.Line2D at 0x1d01f029910>]

- 정리
- 선형 회귀: 예측 회귀선을 직선으로 표현
- 회귀 트리: 분할되는 데이터 지점에 따라 브랜치를 만들며 계단 형태로 회귀선을 만듦
- DecisionTreeRegressor의 max_depth = 7인 경우, 학습 데이터 세트의 이상치(outlier) 데이터도 학습하면서 복잡한 계단 형태의 회귀선을 만들어 과적합 되기 쉬운 모델이 됨
09. 회귀 실습- 자전거 대여 수요 예측
- 데이터 설명
- 기간: 2011년 1월 - 2012년 12월
- 날짜/시간, 기온, 습도, 풍속 등 정보
- 1시간 간격으로 자전거 대여 횟수 기록
- 데이터의 주요 칼럼 (결정값: count)
- datetime: hourly date + timestamp
- season: 1 = 봄, 2 = 여름, 3 = 가을, 4 = 겨울
- holiday: 1= 토/일요일의 주말 제외한 국경일 등의 휴일, 0 = 휴일 아닌 날
- workingday: 1 = 토/일요일의 주말 및 휴일이 아닌 주중, 0 = 주말 및 휴일
- weather: 1 = 맑음, 약간 구름 낀 흐림, 2 = 안개, 안개 + 흐림, 3 = 가벼운 눈, 가벼운 비 + 천둥, 4 = 심한 눈/비, 천둥/번개
- temp: 온도(섭씨)
- atemp: 체감온도(섭씨)
- humidity: 상대습도
- windspeed: 풍속
- casual: 사전 등록되지 않은 사용자 대여 횟수
- registered: 사전 등록된 사용자 대여 횟수
- count: 대여 횟수 (casual + registered)
(1) 데이터 클렌징 및 가공
- bike_train.csv 데이터 세트로 모델을 학습한 후, 대여 횟수(count) 예측
1 | import numpy as np |
(10886, 12)
| datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0 | 3 | 13 | 16 |
| 1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 8 | 32 | 40 |
| 2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 5 | 27 | 32 |
1 | # 데이터 타입 살펴보기 |
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10886 entries, 0 to 10885
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 datetime 10886 non-null object
1 season 10886 non-null int64
2 holiday 10886 non-null int64
3 workingday 10886 non-null int64
4 weather 10886 non-null int64
5 temp 10886 non-null float64
6 atemp 10886 non-null float64
7 humidity 10886 non-null int64
8 windspeed 10886 non-null float64
9 casual 10886 non-null int64
10 registered 10886 non-null int64
11 count 10886 non-null int64
dtypes: float64(3), int64(8), object(1)
memory usage: 1020.7+ KB
- 데이터 타입 확인
- Null 데이터 없음
- datetime 칼럼만 object형, 년-월-일 시:분:초 형식 가공 필요
1 | # 문자열을 datetime 타입으로 변경. |
| datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | year | month | day | hour | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0 | 3 | 13 | 16 | 2011 | 1 | 1 | 0 |
| 1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 8 | 32 | 40 | 2011 | 1 | 1 | 1 |
| 2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0 | 5 | 27 | 32 | 2011 | 1 | 1 | 2 |
1 | # datetime 삭제 |
- 다양한 회귀 모델을 데이터 세트에 적용해 예측 성능 측정하기
- 캐글에서 요구한 성능 평가 방법은 RMSLE(Root Mean Square Log Error)로 오류 값 로그에 대한 RMSE
- 단, 사이킷런은 RMSLE를 제공하지 않아 RMSLE를 수행하는 성능 형가 함수를 만들어야 함
1 | from sklearn.metrics import mean_squared_error, mean_absolute_error |
(2) 로그 변환, 피처 인코딩, 모델 학습/예측/평가
- 회귀 모델을 이용해 자전거 대여 횟수 예측하기
- 먼저, 결괏값이 정규 분포로 되어 있는지 확인해야 함
- 카테고리형 회귀 모델은 원-핫 인코딩으로 피처를 인코딩해야 함
- 사이킷런의 LinearRegression 객체로 회귀 예측하기
1 | from sklearn.model_selection import train_test_split , GridSearchCV |
RMSLE: 1.165, RMSE: 140.900, MAE: 105.924
- 결과 해석
- 실제 Target 데이터 값인 대여 횟수(Count)를 감안하면 예측 오류로서는 비교적 큰 값
- 실제값과 예측값이 어느 정도 차이 나는지 DataFrame 칼럼으로 만들어서 오류 값이 가장 큰 순으로 5개만 확인하기
1 | def get_top_error_data(y_test, pred, n_tops = 5): |
real_count predicted_count diff
1618 890 322.0 568.0
3151 798 241.0 557.0
966 884 327.0 557.0
412 745 194.0 551.0
2817 856 310.0 546.0
- 결과 해석
- 가장 큰 상위 5 오류값은 546 - 568로 실제값을 감안하면 오류가 꽤 큼
- 회귀에서 큰 예측 오류가 발생할 경우, Target 값의 분포가 왜곡된 형태를 이루는지를 확인해야 함
- Target 값 분포는 정규 분포 형태가 가장 좋으며, 왜곡된 경우에는 회귀 예측 성능이 저하되는 경우가 쉽게 발생
- 판다스 DataFrame의 hist()를 이용해 자전거 대여 모델의 Target 값인 count 칼럼이 정규 분포를 이루는지 확인하기
1 | y_target.hist() |
<matplotlib.axes._subplots.AxesSubplot at 0x1d0203fafd0>

- 결과 해석
- count 칼럼 값이 정규 분포가 아닌, 0 - 200 사이에 왜곡된 것을 알 수 있음
- 왜곡된 값을 정규 분포 형태로 바꾸는 방법: 로그를 적용해 변환하는 것
- Numpy의 log1p()이용
- 변경된 Target 값을 기반으로 학습하고, 예측한 값은 expm1() 함수를 이용해 원래의 scale 값으로 원상 복구
- lop1p()를 적용한 ‘count’값이 분포 확인하기
1 | y_log_transform = np.log1p(y_target) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d01ef87c10>

- 정규 분포 형태는 아니지만, 왜곡 정도가 많이 향상됨
- 위 데이터로 다시 학습하고 평가하기
1 | # 타겟 컬럼인 count 값을 log1p 로 Log 변환 |
RMSLE: 1.017, RMSE: 162.594, MAE: 109.286
- RMSLE 오류는 줄어들었으나, RMSE는 오히려 더 늘어남
- 각 피처의 회귀 계수 값을 시각화해 확인하기
1 | coef = pd.Series(lr_reg.coef_, index=X_features.columns) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d020439100>

- 결과 해석
- Year 피처 회귀 계수 값이 독보적으로 큼
- Year는 2011, 2012 두 개의 값으로, year에 따라 자전거 대여 횟수가 크게 영향을 받는다고 할 수 없음
- Category 피처지만 숫자형 값으로 되어 있고 2011, 2012가 매우 큰 숫자라 영향을 주게 됨
- 원-핫 인코딩을 적용해 변환하여야 함
- Year 피처 회귀 계수 값이 독보적으로 큼
- 여러 칼럼 원-핫 인코딩하고 선형 회귀 모델(LinearRegression, Ridge, Lasso) 모두 학습해 예측 성능 확인하기
- 사용 함수: get_model_predict()
- 모델과 학습/테스트 데이터 세트를 입력하면 성능 평가 수치를 반환하는 함수
1 | # 'year', month', 'day', hour'등의 피처들을 One Hot Encoding |
1 | # 원-핫 인코딩이 적용된 feature 데이터 세트 기반으로 학습/예측 데이터 분할. |
### LinearRegression ###
RMSLE: 0.590, RMSE: 97.688, MAE: 63.382
### Ridge ###
RMSLE: 0.590, RMSE: 98.529, MAE: 63.893
### Lasso ###
RMSLE: 0.635, RMSE: 113.219, MAE: 72.803
- 결과 해석
- 원-핫 인코딩 적용 후, 선형 회귀 예측 성능이 많이 향상됨
- 원-핫 인코딩으로 피처가 늘어났으므로, 회귀 계수 상위 25개 피처를 추출해 시각화하기
1 | coef = pd.Series(lr_reg.coef_ , index=X_features_ohe.columns) |
<matplotlib.axes._subplots.AxesSubplot at 0x1d0204cb2e0>

- 결과 해석
- 선형 회귀 모델 시 month_9, month_8, month_7 등의 월 관련 피처와 workingday 관련 피처, hour 관련 피처의 회귀 계수가 높은 것을 알 수 있음
- 월, 주말/주중, 시간대 등 상식선에서 자전거 타는 데 필요한 피처의 회귀 계수가 높아짐
→ 선형 회귀 수행 시에는 피처를 어떻게 인코딩하는가가 성능에 큰 영향을 미칠 수 있음
- 월, 주말/주중, 시간대 등 상식선에서 자전거 타는 데 필요한 피처의 회귀 계수가 높아짐
- 선형 회귀 모델 시 month_9, month_8, month_7 등의 월 관련 피처와 workingday 관련 피처, hour 관련 피처의 회귀 계수가 높은 것을 알 수 있음
- 회귀 트리로 회귀 예측 수행하기
1 | from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor |
### RandomForestRegressor ###
RMSLE: 0.355, RMSE: 50.447, MAE: 31.270
### GradientBoostingRegressor ###
RMSLE: 0.330, RMSE: 53.336, MAE: 32.746
### XGBRegressor ###
RMSLE: 0.342, RMSE: 51.732, MAE: 31.251
### LGBMRegressor ###
RMSLE: 0.319, RMSE: 47.215, MAE: 29.029
- 결과 해석
- 앞의 선형 회귀 모델보다 회귀 예측 성능이 개선됨
- 단, 회귀 트리가 선형 트리보다 나은 성능을 가진다는 의미가 아님
- 데이터 세트 유형에 따라 결과는 얼마든지 달라질 수 있음
10. 회귀 실습- 캐글 주택 가격: 고급 회귀 기법
데이터 설명
- 변수: 79개
- 미국 아이오와주의 에임스(Ames) 지방 주택 가격 정보
- 피처별 설명 확인하기
성능 평가
- RMSLE(Root Mean Squared Log Error) 기반
- 가격이 비싼 주택일수록 예측 결과 오류가 전체 오류에 미치는 비중이 높으므로, 이를 상쇄하기 위해 오류 값을 로그 변환한 RMSLE를 이용
(1) 데이터 사전 처리(Preprocessing)
1 | import warnings |
| Id | MSSubClass | MSZoning | LotFrontage | LotArea | Street | Alley | LotShape | LandContour | Utilities | ... | PoolArea | PoolQC | Fence | MiscFeature | MiscVal | MoSold | YrSold | SaleType | SaleCondition | SalePrice | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 60 | RL | 65.0 | 8450 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2008 | WD | Normal | 208500 |
| 1 | 2 | 20 | RL | 80.0 | 9600 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 5 | 2007 | WD | Normal | 181500 |
| 2 | 3 | 60 | RL | 68.0 | 11250 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 9 | 2008 | WD | Normal | 223500 |
3 rows × 81 columns
1 | # 데이터 세트 전체 크기와 칼럼 타입, Null이 있는 칼럼과 건수를 내림차순으로 출력 |
데이터 세트의 Shape: (1460, 81)
전체 feature 들의 type
object 43
int64 35
float64 3
dtype: int64
Null 컬럼과 그 건수:
PoolQC 1453
MiscFeature 1406
Alley 1369
Fence 1179
FireplaceQu 690
LotFrontage 259
GarageYrBlt 81
GarageType 81
GarageFinish 81
GarageQual 81
GarageCond 81
BsmtFinType2 38
BsmtExposure 38
BsmtFinType1 37
BsmtCond 37
BsmtQual 37
MasVnrArea 8
MasVnrType 8
Electrical 1
dtype: int64
- 데이터 타입 확인
- 테이터 세트는 1460개의 레코드와 81개의 피처로 구성
- 피처 타입은 숫자형과 문자형 모두 존재
- Target을 제외한 80개 피처 중, 43개가 문자형이고 37개가 숫자형
- 1480개 데이터 중, PoolQC, MiseFeature, Alley, Fence는 1000개가 넘는 Null 값을 가짐
- Null 값이 너무 많은 피처는 drop
- 회귀 모델 적용 전, 타깃 값 분포가 정규 분포인지 확인하기
- 아래 그래프에서 볼 수 있듯, 데이터 값 분포가 왼쪽으로 치우친 형태로 정규 분포에서 벗어나 있음
1 | plt.title('Original Sale Price Histogram') |
<matplotlib.axes._subplots.AxesSubplot at 0x1d017a30310>

- 로그 변환(Log Transformation)을 적용하여, 정규 분포가 아닌 결괏값을 정규 분포 형태로 변환하기
- Numpy의 log1p()로 로그 변환한 결괏값 기반으로 학습
- 예측 시에는 결괏값을 expm1()로 환원
1 | plt.title('Log Transformed Sale Price Histogram') |
<matplotlib.axes._subplots.AxesSubplot at 0x1d017b1a790>

- SalePrice를 로그 변환해 정규 분포 형태로 결괏값이 분포함을 확인할 수 있음
- 다음 작업
- SalePrice를 로그 변환하고 DataFrame에 반영
- Null 값이 많은 피처인 PoolQC, MiseFeature, Alley, Fence, FireplaceQu 삭제
- 단순 식별자인 Id 삭제
- LotFrontage Null 값은 259개로 비교적 많으나, 평균값으로 대체
- 나머지 피처 Null 값은 많지 않으므로 숫자형의 경우 평균값으로 대체
1 | # SalePrice 로그 변환 |
## Null 피처의 Type :
MasVnrType object
BsmtQual object
BsmtCond object
BsmtExposure object
BsmtFinType1 object
BsmtFinType2 object
Electrical object
GarageType object
GarageFinish object
GarageQual object
GarageCond object
dtype: object
- 문자형 피처는 원-핫 인코딩으로 변환하기
- 사용 함수: get_dummies()
- 자동으로 문자열 피처를 원-핫 인코딩으로 변환하면서 Null 값을 ‘None’ 칼럼으로 대체해주어 Null 값을 대체하는 별도의 로직이 필요 없음
- 원-핫 인코딩을 적용하면 칼럼이 증가하기 때문에, 변환 후 늘어난 칼럼 값까지 확인하기
1 | print('get_dummies() 수행 전 데이터 Shape:', house_df.shape) |
get_dummies() 수행 전 데이터 Shape: (1460, 75)
get_dummies() 수행 후 데이터 Shape: (1460, 271)
## Null 피처의 Type :
Series([], dtype: object)
- 결과 해석
- 원-핫 인코딩 후 피처가 75개에서 272개로 증가
- Null 값을 가진 피처는 없음
(2) 선형 회귀 모델 학습/예측/평가
RMSE 평가 함수 생성
1 | def get_rmse(model): |
LinearRegression, Ridge, Lasso 학습, 예측, 평가
1 | from sklearn.model_selection import train_test_split |
LinearRegression 로그 변환된 RMSE: 0.132
Ridge 로그 변환된 RMSE: 0.128
Lasso 로그 변환된 RMSE: 0.176
[0.1318957657915403, 0.1275084633405302, 0.17628250556471403]
회귀 계수값과 컬럼명 시각화를 위해 상위 10개, 하위 10개(-값으로 가장 큰 10개) 회귀 계수값과 컬럼명을 가지는 Series생성 함수.
1 | def get_top_bottom_coef(model): |
인자로 입력되는 여러개의 회귀 모델들에 대한 회귀계수값과 컬럼명 시각화
1 | def visualize_coefficient(models): |

5 폴드 교차검증으로 모델별로 RMSE와 평균 RMSE출력
1 | from sklearn.model_selection import cross_val_score |
LinearRegression CV RMSE 값 리스트: [0.135 0.165 0.168 0.111 0.198]
LinearRegression CV 평균 RMSE 값: 0.155
Ridge CV RMSE 값 리스트: [0.117 0.154 0.142 0.117 0.189]
Ridge CV 평균 RMSE 값: 0.144
Lasso CV RMSE 값 리스트: [0.161 0.204 0.177 0.181 0.265]
Lasso CV 평균 RMSE 값: 0.198
각 모델들의 alpha값을 변경하면서 하이퍼 파라미터 튜닝 후 다시 학습/예측/평가
1 | from sklearn.model_selection import GridSearchCV |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1418, 최적 alpha:{'alpha': 12}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.142, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.132
Ridge 로그 변환된 RMSE: 0.124
Lasso 로그 변환된 RMSE: 0.12

숫자 피처들에 대한 데이터 분포 왜곡도 확인 후 높은 왜곡도를 가지는 피처 추출
1 | from scipy.stats import skew # skew: 왜곡 |
MiscVal 24.451640
PoolArea 14.813135
LotArea 12.195142
3SsnPorch 10.293752
LowQualFinSF 9.002080
KitchenAbvGr 4.483784
BsmtFinSF2 4.250888
ScreenPorch 4.117977
BsmtHalfBath 4.099186
EnclosedPorch 3.086696
MasVnrArea 2.673661
LotFrontage 2.382499
OpenPorchSF 2.361912
BsmtFinSF1 1.683771
WoodDeckSF 1.539792
TotalBsmtSF 1.522688
MSSubClass 1.406210
1stFlrSF 1.375342
GrLivArea 1.365156
dtype: float64
왜곡도가 1인 피처들은 로그 변환 적용하고 다시 하이퍼 파라미터 튜닝 후 재 학습/예측/평가
1 | house_df[skew_features_top.index] = np.log1p(house_df[skew_features_top.index]) |
1 | # Skew가 높은 피처들을 로그 변환 했으므로 다시 원-핫 인코딩 적용 및 피처/타겟 데이터 셋 생성, |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1275, 최적 alpha:{'alpha': 10}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.1252, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.128
Ridge 로그 변환된 RMSE: 0.122
Lasso 로그 변환된 RMSE: 0.119

이상치 데이터 검출을 위해 주요 피처인 GrLivArea값에 대한 산포도 확인
1 | plt.scatter(x = house_df_org['GrLivArea'], y = house_df_org['SalePrice']) |

이상치 데이터 삭제 후 재 학습/예측/평가
1 | # GrLivArea와 SalePrice 모두 로그 변환되었으므로 이를 반영한 조건 생성. |
아웃라이어 레코드 index : [ 523 1298]
아웃라이어 삭제 전 house_df_ohe shape: (1460, 271)
아웃라이어 삭제 후 house_df_ohe shape: (1458, 271)
1 | y_target = house_df_ohe['SalePrice'] |
Ridge 5 CV 시 최적 평균 RMSE 값: 0.1125, 최적 alpha:{'alpha': 8}
Lasso 5 CV 시 최적 평균 RMSE 값: 0.1122, 최적 alpha:{'alpha': 0.001}
1 | # 앞의 최적화 alpha값으로 학습데이터로 학습, 테스트 데이터로 예측 및 평가 수행. |
LinearRegression 로그 변환된 RMSE: 0.129
Ridge 로그 변환된 RMSE: 0.103
Lasso 로그 변환된 RMSE: 0.1

(3) 회귀 트리 학습/예측/평가
XGBoost와 LightGBM 학습/예측/평가
1 | from xgboost import XGBRegressor |
XGBRegressor 5 CV 시 최적 평균 RMSE 값: 0.1178, 최적 alpha:{'n_estimators': 1000}
1 | from lightgbm import LGBMRegressor |
LGBMRegressor 5 CV 시 최적 평균 RMSE 값: 0.1163, 최적 alpha:{'n_estimators': 1000}
트리 회귀 모델의 피처 중요도 시각화
1 | # 모델의 중요도 상위 20개의 피처명과 그때의 중요도값을 Series로 반환. |

(4) 회귀 모델들의 예측 결과 혼합을 통한 최종 예측
1 | def get_rmse_pred(preds): |
최종 혼합 모델의 RMSE: 0.10007930884470519
Ridge 모델의 RMSE: 0.10345177546603257
Lasso 모델의 RMSE: 0.10024170460890033
1 | xgb_reg = XGBRegressor(n_estimators=1000, learning_rate=0.05, |
최종 혼합 모델의 RMSE: 0.1017007808403327
XGBM 모델의 RMSE: 0.10738299364833828
LGBM 모델의 RMSE: 0.10382510019327311
(5) 스태킹 모델을 통한 회귀 예측
1 | from sklearn.model_selection import KFold |
기반 모델은 리지, 라소, XGBoost, LightGBM 으로 만들고 최종 메타 모델은 라소로 생성하여 학습/예측/평가
1 | # get_stacking_base_datasets( )은 넘파이 ndarray를 인자로 사용하므로 DataFrame을 넘파이로 변환. |
Ridge model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
Lasso model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
XGBRegressor model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
LGBMRegressor model 시작
폴드 세트: 0 시작
폴드 세트: 1 시작
폴드 세트: 2 시작
폴드 세트: 3 시작
폴드 세트: 4 시작
1 | # 개별 모델이 반환한 학습 및 테스트용 데이터 세트를 Stacking 형태로 결합. |
스태킹 회귀 모델의 최종 RMSE 값은: 0.09799154066897717
11. 정리
- 선형 회귀와 비용 함수 RSS
- 경사 하강법
- 다항회귀와 과소적합/과대적합
- 규제 -L2규제를 적용한 릿지, L1규제를 적용한 라쏘, L1과 L2규제가 결합된 엘라스틱넷 회귀
- 분류를 위한 로지스틱 회귀
- CART 기반의 회귀 트리
- 왜곡도 개선을 위한 데이터 변환과 원-핫 인코딩
- 실습 예제를 통한 데이터 정제와 변환 그리고 선형회귀/회귀트리/혼합모델/스태킹 모델 학습/예측/평가비교